/*
* Copyright (c) 2012 Kyle Hayward
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "Precompiled.h"

#include "CompiledCuda.h"

using namespace System;
using namespace System::IO;

namespace OptixDotNet
{
	CompiledCuda::CompiledCuda( const char* compiledSource )
	{
		mCompiledSource = AnsiiToStr( compiledSource );
	}

	void CompiledCuda::Save( String^ path )
	{
		StreamWriter^ stream = gcnew StreamWriter( path );
		stream->Write( mCompiledSource );

		stream->Close();
	}

	CompiledCuda^ CompiledCuda::CompileFromFile( String^ fileName, array<String^>^ preprocessorArgs )
	{
		return CompiledCuda::Compile( fileName, preprocessorArgs, true );
	}

	CompiledCuda^ CompiledCuda::CompileFromString( String^ source, array<String^>^ preprocessorArgs )
	{
		return CompiledCuda::Compile( source, preprocessorArgs, false );
	}

	CompiledCuda^ CompiledCuda::Compile( System::String^ source, array<System::String^>^ preprocessorArgs, bool fromFile )
	{
		if( String::IsNullOrEmpty( source ) )
			throw gcnew System::Exception( "CompiledCuda Error: Empty or Null file name" );

		int numArgs = 0;
		const char** args = 0;

		if( preprocessorArgs != nullptr && preprocessorArgs->Length > 0 )
		{
			args = new const char*[ preprocessorArgs->Length ];
			numArgs = preprocessorArgs->Length;

			for( int i = 0; i < numArgs; i++ )
			{
				args[i] = StrToAnsii( preprocessorArgs[i] );
			}
		}

		RTsize resultSize;
		RTsize errorSize;

		if( fromFile )
			rtuCUDACompileFile( StrToAnsii( source ), args, numArgs, &resultSize, &errorSize );
		else
			rtuCUDACompileString( StrToAnsii( source ), args, numArgs, &resultSize, &errorSize );

		char* result = 0;
		char* error = 0;

		if( resultSize > 0 )
			result = new char[ resultSize ];

		if( errorSize > 0 )
			error = new char[ errorSize ];

		rtuCUDAGetCompileResult( result, error );

		if( errorSize > 0 )
		{
			String^ errorString = AnsiiToStr( error );

			String^ exception = String::Format( "CompiledCuda Error: Error compiling CUDA source {0}: {1}", source, errorString );

			delete[] error;
			delete[] args;

			if( result )
				delete[] result;

			throw gcnew System::Exception( exception );
		}

		CompiledCuda^ compiled = gcnew CompiledCuda( result );

		delete[] result;
		delete[] args;

		if( error )
			delete[] error;

		return compiled;
	}
}